Implement trigger postinstall API Test: adb shell update_engine_client --trigger_postinstall=system Bug: 377557752 Change-Id: Ieb28e86bd979502c5b208cd8df917f3e49a50f0b 
diff --git a/aosp/service_delegate_android_interface.h b/aosp/service_delegate_android_interface.h index c73c6de..5e139d7 100644 --- a/aosp/service_delegate_android_interface.h +++ b/aosp/service_delegate_android_interface.h 
@@ -17,8 +17,6 @@  #ifndef UPDATE_ENGINE_AOSP_SERVICE_DELEGATE_ANDROID_INTERFACE_H_  #define UPDATE_ENGINE_AOSP_SERVICE_DELEGATE_ANDROID_INTERFACE_H_   -#include <inttypes.h> -  #include <memory>  #include <string>  #include <vector> 
diff --git a/aosp/update_attempter_android.cc b/aosp/update_attempter_android.cc index f29383a..89c79f3 100644 --- a/aosp/update_attempter_android.cc +++ b/aosp/update_attempter_android.cc 
@@ -17,6 +17,7 @@  #include "update_engine/aosp/update_attempter_android.h"    #include <algorithm> +#include <iterator>  #include <map>  #include <memory>  #include <ostream> @@ -56,6 +57,7 @@  #include "update_engine/payload_consumer/payload_verifier.h"  #include "update_engine/payload_consumer/postinstall_runner_action.h"  #include "update_engine/update_boot_flags_action.h" +#include "update_engine/update_metadata.pb.h"  #include "update_engine/update_status.h"  #include "update_engine/update_status_utils.h"   @@ -546,6 +548,32 @@  return !(a == b);  }   +bool VerifyPayloadMetadata(Error* error, + std::string_view metadata, + const PayloadMetadata& payload_metadata) { + auto payload_verifier = PayloadVerifier::CreateInstanceFromZipPath( + constants::kUpdateCertificatesPath); + if (!payload_verifier) { + return LogAndSetError(error, + __LINE__, + __FILE__, + "Failed to create the payload verifier from " + + std::string(constants::kUpdateCertificatesPath), + ErrorCode::kDownloadManifestParseError); + } + auto errorcode = payload_metadata.ValidateMetadataSignature( + metadata, "", *payload_verifier); + if (errorcode != ErrorCode::kSuccess) { + return LogAndSetError(error, + __LINE__, + __FILE__, + "Failed to validate metadata signature: " + + utils::ErrorCodeToString(errorcode), + errorcode); + } + return true; +} +  bool UpdateAttempterAndroid::VerifyPayloadParseManifest(  const std::string& metadata_filename,  std::string_view expected_metadata_hash, @@ -619,27 +647,9 @@  << HexEncode(metadata_hash);  }  } + TEST_AND_RETURN_FALSE( + VerifyPayloadMetadata(error, ToStringView(metadata), payload_metadata));   - auto payload_verifier = PayloadVerifier::CreateInstanceFromZipPath( - constants::kUpdateCertificatesPath); - if (!payload_verifier) { - return LogAndSetError(error, - __LINE__, - __FILE__, - "Failed to create the payload verifier from " + - std::string(constants::kUpdateCertificatesPath), - ErrorCode::kDownloadManifestParseError); - } - errorcode = payload_metadata.ValidateMetadataSignature( - metadata, "", *payload_verifier); - if (errorcode != ErrorCode::kSuccess) { - return LogAndSetError(error, - __LINE__, - __FILE__, - "Failed to validate metadata signature: " + - utils::ErrorCodeToString(errorcode), - errorcode); - }  if (!payload_metadata.GetManifest(metadata, manifest)) {  return LogAndSetError(error,  __LINE__, @@ -1454,16 +1464,162 @@  processor_->StartProcessing();  }   +bool ParsePayloadMetadata(Error* error, + std::string_view manifest_bytes, + DeltaArchiveManifest* manifest) { + PayloadMetadata payload_metadata; + ErrorCode errorcode{}; + if (payload_metadata.ParsePayloadHeader(manifest_bytes, &errorcode) != + MetadataParseResult::kSuccess) { + return LogAndSetError(error, + __LINE__, + __FILE__, + "Failed to parse payload header: " + + utils::ErrorCodeToString(errorcode), + errorcode); + } + uint64_t metadata_size = payload_metadata.GetMetadataSize() + + payload_metadata.GetMetadataSignatureSize(); + if (metadata_size < kMaxPayloadHeaderSize || + metadata_size > manifest_bytes.size()) { + return LogAndSetError(error, + __LINE__, + __FILE__, + "Invalid metadata size on cached manifest: " + + std::to_string(metadata_size), + ErrorCode::kDownloadManifestParseError); + } + TEST_AND_RETURN_FALSE( + VerifyPayloadMetadata(error, manifest_bytes, payload_metadata)); + + if (!payload_metadata.GetManifest(manifest_bytes, manifest)) { + return LogAndSetError(error, + __LINE__, + __FILE__, + "Failed to parse manifest. Might need to install " + "OTA first and re-try this API", + ErrorCode::kDownloadManifestParseError); + } + return true; +} +  bool UpdateAttempterAndroid::TriggerPostinstall(const std::string& partition,  Error* error) { - if (error) { - return LogAndSetGenericError( + if (processor_->IsRunning()) { + return LogAndSetError(error, + __LINE__, + __FILE__, + "Already processing an update, cancel it first.", + ErrorCode::kUpdateProcessing); + } + bool postinstall_succeeded = false; + if (!prefs_->GetBoolean(kPrefsPostInstallSucceeded, &postinstall_succeeded)) { + return LogAndSetError(  error,  __LINE__,  __FILE__, - __FUNCTION__ + std::string(" is not implemented")); + "Postinstall action did not run. " + "OTA update must first reach the " + "Postinstall phase(which verfies that all partitions can be mounted) " + "before calling TriggerPostinstall", + ErrorCode::kPostinstallRunnerError);  } - return false; + if (!postinstall_succeeded) { + return LogAndSetError( + error, + __LINE__, + __FILE__, + "Postinstall action did not complete successfully. " + "OTA update must first reach the " + "Postinstall phase(which verfies that all partitions can be mounted) " + "before calling TriggerPostinstall", + ErrorCode::kPostinstallRunnerError); + } + + InstallPlan install_plan; + install_plan.source_slot = GetCurrentSlot(); + install_plan.target_slot = GetTargetSlot(); + install_plan.switch_slot_on_reboot = false; + install_plan.run_post_install = true; + install_plan.download_url = + std::string(kPrefsManifestBytes) + ":" + install_plan_.download_url; + + std::string manifest_bytes; + // kPrefsManifestBytes is set during DownloadAction + if (!prefs_->GetString(kPrefsManifestBytes, &manifest_bytes)) { + return LogAndSetError( + error, + __LINE__, + __FILE__, + "Cached manifest not found. TriggerPostinstall can only be called " + "after OTA get past at least FilesystemVerification stage", + ErrorCode::kDownloadStateInitializationError); + } + DeltaArchiveManifest manifest; + TEST_AND_RETURN_FALSE(ParsePayloadMetadata(error, manifest_bytes, &manifest)); + ErrorCode errorcode{}; + if (!boot_control_->GetDynamicPartitionControl()->PreparePartitionsForUpdate( + GetCurrentSlot(), + GetTargetSlot(), + manifest, + false /* should update */, + nullptr, + &errorcode)) { + return LogAndSetError(error, + __LINE__, + __FILE__, + "Failed to PreparePartitionsForUpdate", + errorcode); + } + std::vector<PartitionUpdate> partitions; + std::copy_if(manifest.partitions().begin(), + manifest.partitions().end(), + std::back_inserter(partitions), + [&partition](const PartitionUpdate& part) { + return part.partition_name() == partition; + }); + if (partitions.empty()) { + return LogAndSetError(error, + __LINE__, + __FILE__, + "Partition " + partition + " not found", + ErrorCode::kDownloadStateInitializationError); + } + // We only want to trigger postinstall for a specific partition, + // and since we already checked partitions array is non-empty, reading just + // the first partition is enough. + if (!partitions[0].has_postinstall_path() || + partitions[0].postinstall_path().empty()) { + return LogAndSetError(error, + __LINE__, + __FILE__, + "Partition " + partition + + " does not have a postinstall script defined", + ErrorCode::kDownloadStateInitializationError); + } + if (!install_plan.ParsePartitions( + partitions, boot_control_, manifest.block_size(), &errorcode)) { + return LogAndSetError(error, + __LINE__, + __FILE__, + "Failed to parse manifest partitions. Might need " + "to install OTA first and re-try this API", + ErrorCode::kDownloadManifestParseError); + } + LOG(INFO) << "Trigger postinstall with this install plan: " + << install_plan.ToString(); + + auto postinstall_runner_action = + std::make_unique<PostinstallRunnerAction>(boot_control_, hardware_); + postinstall_runner_action->set_delegate(this); + + auto install_plan_action = std::make_unique<InstallPlanAction>(install_plan); + BondActions(install_plan_action.get(), postinstall_runner_action.get()); + processor_->EnqueueAction(std::move(install_plan_action)); + processor_->EnqueueAction(std::move(postinstall_runner_action)); + SetStatusAndNotify(UpdateStatus::FINALIZING); + ScheduleProcessingStart(); + return true;  }    void UpdateAttempterAndroid::OnCleanupProgressUpdate(double progress) { 
diff --git a/payload_consumer/filesystem_verifier_action.cc b/payload_consumer/filesystem_verifier_action.cc index 8c21673..956f90b 100644 --- a/payload_consumer/filesystem_verifier_action.cc +++ b/payload_consumer/filesystem_verifier_action.cc 
@@ -16,7 +16,6 @@    #include "update_engine/payload_consumer/filesystem_verifier_action.h"   -#include <errno.h>  #include <fcntl.h>  #include <sys/stat.h>  #include <sys/types.h> @@ -28,7 +27,6 @@  #include <memory>  #include <numeric>  #include <string> -#include <utility>    #include <base/bind.h>  #include <brillo/data_encoding.h> 
diff --git a/payload_consumer/payload_metadata.cc b/payload_consumer/payload_metadata.cc index d2e42f0..649d9be 100644 --- a/payload_consumer/payload_metadata.cc +++ b/payload_consumer/payload_metadata.cc 
@@ -154,7 +154,7 @@  }    ErrorCode PayloadMetadata::ValidateMetadataSignature( - const brillo::Blob& payload, + const std::string_view payload,  const string& metadata_signature,  const PayloadVerifier& payload_verifier) const {  if (payload.size() < metadata_size_ + metadata_signature_size_) 
diff --git a/payload_consumer/payload_metadata.h b/payload_consumer/payload_metadata.h index 4d2d5b0..fd24f20 100644 --- a/payload_consumer/payload_metadata.h +++ b/payload_consumer/payload_metadata.h 
@@ -17,14 +17,12 @@  #ifndef UPDATE_ENGINE_PAYLOAD_CONSUMER_PAYLOAD_METADATA_H_  #define UPDATE_ENGINE_PAYLOAD_CONSUMER_PAYLOAD_METADATA_H_   -#include <inttypes.h> -  #include <string> -#include <vector>    #include <android-base/macros.h>  #include <brillo/secure_blob.h>   +#include "update_engine/common/utils.h"  #include "update_engine/common/error_code.h"  #include "update_engine/payload_consumer/payload_verifier.h"  #include "update_engine/update_metadata.pb.h" @@ -55,6 +53,12 @@  // the payload.  MetadataParseResult ParsePayloadHeader(const brillo::Blob& payload,  ErrorCode* error); + MetadataParseResult ParsePayloadHeader(std::string_view payload, + ErrorCode* error) { + return ParsePayloadHeader(reinterpret_cast<const uint8_t*>(payload.data()), + payload.size(), + error); + }  MetadataParseResult ParsePayloadHeader(const unsigned char* payload,  size_t size,  ErrorCode* error); @@ -69,9 +73,16 @@  // to the payload server doesn't exploit any vulnerability in the code that  // parses the protocol buffer.  ErrorCode ValidateMetadataSignature( - const brillo::Blob& payload, + std::string_view payload,  const std::string& metadata_signature,  const PayloadVerifier& payload_verifier) const; + ErrorCode ValidateMetadataSignature( + const std::vector<uint8_t>& payload, + const std::string& metadata_signature, + const PayloadVerifier& payload_verifier) const { + return ValidateMetadataSignature( + ToStringView(payload), metadata_signature, payload_verifier); + }    // Returns the major payload version. If the version was not yet parsed,  // returns zero. @@ -93,6 +104,12 @@  bool GetManifest(const unsigned char* payload,  size_t size,  DeltaArchiveManifest* out_manifest) const; + bool GetManifest(std::string_view payload, + DeltaArchiveManifest* out_manifest) const { + return GetManifest(reinterpret_cast<const uint8_t*>(payload.data()), + payload.size(), + out_manifest); + }    // Parses a payload file |payload_path| and prepares the metadata properties,  // manifest and metadata signatures. Can be used as an easy to use utility to 
diff --git a/payload_consumer/postinstall_runner_action.cc b/payload_consumer/postinstall_runner_action.cc index 5a6eeab..da9075a 100644 --- a/payload_consumer/postinstall_runner_action.cc +++ b/payload_consumer/postinstall_runner_action.cc 
@@ -35,7 +35,6 @@  #include "update_engine/common/action_processor.h"  #include "update_engine/common/boot_control_interface.h"  #include "update_engine/common/error_code_utils.h" -#include "update_engine/common/platform_constants.h"  #include "update_engine/common/subprocess.h"  #include "update_engine/common/utils.h"   @@ -280,14 +279,20 @@  // Runs the postinstall script asynchronously to free up the main loop while  // it's running.  vector<string> command = {abs_path}; -#ifdef __ANDROID__  // In Brillo and Android, we pass the slot number and status fd.  command.push_back(std::to_string(install_plan_.target_slot));  command.push_back(std::to_string(kPostinstallStatusFd)); -#else - // Chrome OS postinstall expects the target rootfs as the first parameter. - command.push_back(partition.target_path); -#endif // __ANDROID__ + // If install plan only contains one partition, notify the script. Most likely + // we are scheduled by `triggerPostinstall` API. Certain scripts might want + // different behaviors when triggered by `triggerPostinstall` API. For + // example, call scheduler API to schedule a postinstall run during + // applyPayload(), and only run actual postinstall work if scheduled by + // external async scheduler. + if (install_plan_.partitions.size() == 1 && + !install_plan_.switch_slot_on_reboot && + install_plan_.download_url.starts_with(kPrefsManifestBytes)) { + command.push_back("1"); + }    current_command_ = Subprocess::Get().ExecFlags(  command,